home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / unexsunos4.c < prev    next >
C/C++ Source or Header  |  1993-07-23  |  8KB  |  280 lines

  1. /* Contributed by Viktor Dukhovni.  */
  2. /*
  3.  * Unexec for Berkeley a.out format + SUNOS shared libraries
  4.  * The unexeced executable contains the __DYNAMIC area from the
  5.  * original text file,  and then the rest of data + bss + malloced area of
  6.  * the current process.  (The __DYNAMIC area is at the top of the process
  7.  * data segment,  we use "data_start" defined externally to mark the start
  8.  * of the "real" data segment.)
  9.  *
  10.  * For programs that want to remap some of the data segment read only
  11.  * a run_time_remap is provided.  This attempts to remap largest area starting
  12.  * and ending on page boundaries between "data_start" and "bndry"
  13.  * For this it to figure out where the text file is located.  A path search
  14.  * is attempted after trying argv[0] and if all fails we simply do not remap
  15.  *
  16.  * One feature of run_time_remap () is mandatory:  reseting the break.
  17.  *
  18.  *  Note that we can no longer map data into the text segment,  as this causes
  19.  *  the __DYNAMIC struct to become read only,  breaking the runtime loader.
  20.  *  Thus we no longer need to mess with a private crt0.c,  the standard one
  21.  *  will do just fine,  since environ can live in the writable area between
  22.  *  __DYNAMIC and data_start,  just make sure that pre-crt0.o (the name
  23.  *  is somewhat abused here) is loaded first!
  24.  *
  25.  */
  26. #ifdef emacs
  27. #include "config.h"
  28. #endif
  29.  
  30. #include <sys/param.h>
  31. #include <sys/mman.h>
  32. #include <sys/file.h>
  33. #include <sys/stat.h>
  34. #include <string.h>
  35. #include <stdio.h>
  36. #include <a.out.h>
  37.  
  38. /*
  39.  * for programs other than emacs
  40.  * define data_start + initialized here,  and make sure
  41.  * this object is loaded first!
  42.  * emacs will define these elsewhere,  and load the object containing
  43.  * data_start (pre-crt0.o or firstfile.o?) first!
  44.  * The custom crt0.o *must not* be loaded!
  45.  */
  46. #ifndef emacs
  47.   static int data_start = 0;
  48.   static int initialized = 0;
  49. #else
  50.   extern int initialized;
  51.   extern unsigned data_start;
  52.   extern int pureptr;
  53. #endif
  54.  
  55. extern char *getenv ();
  56. static unsigned Brk;
  57. static struct exec nhdr;
  58. static int rd_only_len;
  59. static long cookie;
  60.  
  61.  
  62. unexec (new_name, a_name, bndry, bss_start, entry) 
  63.      char *new_name, *a_name;
  64.      unsigned bndry, bss_start, entry;
  65. {
  66.   char buf[PAGSIZ];
  67.   int fd, new;
  68.   char *old;
  69.   struct exec ohdr;        /* Allocate on the stack,  not needed in the next life */
  70.   struct stat stat;
  71.  
  72. #ifdef emacs
  73.   fprintf (stderr, "Used %d bytes of Pure Storage\n", pureptr);
  74. #endif
  75.  
  76.   if ((fd = open (a_name, O_RDONLY)) < 0)
  77.     {
  78.       fprintf (stderr, "%s: open: ", a_name);
  79.       perror (a_name);
  80.       exit (1);
  81.     }
  82.   if ((new = open (new_name, O_WRONLY | O_CREAT, 0666)) == -1)
  83.     {
  84.       fprintf (stderr, "%s: open: ", a_name);
  85.       perror (new_name);
  86.       exit (1);
  87.     }
  88.  
  89.   if ((fstat (fd, &stat) == -1))
  90.     {
  91.       fprintf (stderr, "%s: ", a_name);
  92.       perror ("fstat");
  93.       exit (1);
  94.     }
  95.  
  96.   old = (char *)mmap (0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
  97.   if (old == (char *)-1)
  98.     {
  99.       fprintf (stderr, "%s: ", a_name);
  100.       perror ("mmap");
  101.       exit (1);
  102.     }
  103.   close (fd);
  104.  
  105.   nhdr = ohdr = (*(struct exec *)old);
  106.  
  107.  
  108.   /*
  109.    * Remember a magic cookie so we know we've got the right binary
  110.    * when remapping.
  111.    */
  112.   cookie = time (0);
  113.  
  114.   Brk = sbrk (0);        /* Save the break, it is reset to &_end (by ld.so?) */
  115.  
  116.   /*
  117.    * Round up data start to a page boundary (Lose if not a 2 power!)
  118.    */
  119.   data_start = ((((int)&data_start) - 1) & ~(N_PAGSIZ (nhdr) - 1)) + N_PAGSIZ (nhdr);
  120.  
  121.   /*
  122.    * Round down read only pages to a multiple of the page size
  123.    */
  124.   if (bndry)
  125.     rd_only_len = ((int)bndry & ~(N_PAGSIZ (nhdr) - 1)) - data_start;
  126.  
  127. #ifndef emacs
  128.   /* Have to do this some time before dumping the data */
  129.   initialized = 1;
  130. #endif
  131.   
  132.   /* 
  133.    * Handle new data and bss sizes and optional new entry point.
  134.    * No one actually uses bss_start and entry,  but tradition compels
  135.    * one to support them.
  136.    * Could complain if bss_start > Brk,  but the caller is *supposed* to know
  137.    * what she is doing.
  138.    */
  139.   nhdr.a_data = (bss_start ? bss_start : Brk) - N_DATADDR (nhdr);
  140.   nhdr.a_bss  = bss_start ? Brk - bss_start : 0;
  141.   if (entry) 
  142.     nhdr.a_entry = entry;
  143.  
  144.   /*
  145.    * Write out the text segment with new header
  146.    * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
  147.    * part of the text segment, but no need to rely on this.
  148.    * So write the TEXT first,  then go back replace the header.
  149.    * Doing it in the other order is less general!
  150.    */
  151.   lseek (new, N_TXTOFF (nhdr), L_SET);
  152.   write (new, old + N_TXTOFF (ohdr), N_TXTOFF (ohdr) + ohdr.a_text);
  153.   lseek (new, 0L, L_SET);
  154.   write (new, &nhdr, sizeof (nhdr));
  155.  
  156.   /*
  157.    * Write out the head of the old data segment from the file not
  158.    * from core, this has the unresolved __DYNAMIC relocation data
  159.    * we need to reload
  160.    */
  161.   lseek (new, N_DATOFF (nhdr), L_SET);
  162.   write (new, old + N_DATOFF (ohdr), (int)&data_start - N_DATADDR (ohdr));
  163.  
  164.   /*
  165.    * Copy the rest of the data from core
  166.    */
  167.   write (new, &data_start, N_BSSADDR (nhdr) - (int)&data_start);
  168.  
  169.   /*
  170.    * Copy the symbol table and line numbers
  171.    */
  172.   lseek (new, N_TRELOFF (nhdr), L_SET);
  173.   write (new, old + N_TRELOFF (ohdr), stat.st_size - N_TRELOFF (ohdr));
  174.  
  175.   fchmod (new, 0755);
  176. }
  177.  
  178. void
  179. run_time_remap (progname)
  180.      char *progname;
  181. {
  182.   char aout[MAXPATHLEN];
  183.   register char *path, *p;
  184.  
  185.   /* Just in case */
  186.   if (!initialized)
  187.     return;
  188.  
  189.   /* Restore the break */
  190.   brk (Brk);
  191.  
  192.   /*  If nothing to remap:  we are done! */
  193.   if (rd_only_len == 0)
  194.     return;
  195.  
  196.   /*
  197.    * Attempt to find the executable
  198.    * First try argv[0],  will almost always succeed as shells tend to give
  199.    * the full path from the hash list rather than using execvp ()
  200.    */
  201.   if (is_it (progname)) 
  202.     return;
  203.  
  204.   /*
  205.    * If argv[0] is a full path and does not exist,  not much sense in
  206.    * searching further
  207.    */
  208.   if (strchr (progname, '/')) 
  209.     return;
  210.  
  211.   /*
  212.    * Try to search for  argv[0] on the PATH
  213.    */
  214.   path = getenv ("PATH");
  215.   if (path == NULL)
  216.     return;
  217.  
  218.   while (*path)
  219.     {
  220.       /* copy through ':' or end */
  221.       for (p = aout; *p = *path; ++p, ++path)
  222.     if (*p == ':')
  223.       {
  224.         ++path;        /* move past ':' */
  225.         break;
  226.       }
  227.       *p++ = '/';
  228.       strcpy (p, progname);
  229.       /*
  230.        * aout is a candidate full path name
  231.        */
  232.       if (is_it (aout))
  233.     return;
  234.     }
  235. }
  236.  
  237. is_it (path)
  238.   char *path;
  239. {
  240.   int fd;
  241.   long paths_cookie;
  242.   struct exec hdr;
  243.  
  244.   /*
  245.    * Open an executable  and check for a valid header!
  246.    * Can't bcmp() the header with what we had,  it may have been stripped!
  247.    * so we may save looking at non executables with the same name, mostly
  248.    * directories.
  249.    */
  250.   fd = open (path, O_RDONLY);
  251.   if (fd != -1)
  252.     {
  253.       if (read (fd, &hdr, sizeof (hdr)) == sizeof (hdr)
  254.       && !N_BADMAG (hdr) && N_DATOFF (hdr) == N_DATOFF (nhdr)
  255.       && N_TRELOFF (hdr) == N_TRELOFF (nhdr))
  256.     {
  257.       /* compare cookies */
  258.       lseek (fd, N_DATOFF (hdr) + (int)&cookie - N_DATADDR (hdr), L_SET);
  259.       read (fd, &paths_cookie, sizeof (paths_cookie));
  260.       if (paths_cookie == cookie)
  261.         {            /* Eureka */
  262.  
  263.           /*
  264.            * Do the mapping
  265.            * The PROT_EXEC may not be needed,  but it is safer this way.
  266.            * should the shared library decide to indirect through
  267.            * addresses in the data segment not part of __DYNAMIC
  268.            */
  269.           mmap (data_start, rd_only_len, PROT_READ | PROT_EXEC,
  270.             MAP_SHARED | MAP_FIXED, fd,
  271.             N_DATOFF (hdr) + data_start - N_DATADDR (hdr));
  272.           close (fd);
  273.           return 1;
  274.         }
  275.     }
  276.       close (fd);
  277.     }
  278.   return 0;
  279. }
  280.